import re
import csv
import time
import copy
from datetime import datetime, date, timedelta
from MA import MovingAverage

class Bar:
  def __init__(self, time, open, close, high, low, vol=0, oi=0):
    self.time = time
    self.open = open
    self.close = close
    self.high = high
    self.low = low
    self.vol = vol
    self.oi = oi
	
  def merge(self, bar):
    if self.time < bar.time:
      self.close = bar.close
    else:
      self.open = bar.open
    self.high = max(self.high, bar.high)
    self.low = min(self.low, bar.low)
    self.oi += bar.oi
    
  def toString(self):
    return "%s,%s,%s,%s,%s"%(self.time, self.open, self.close, self.high, self.low)
	
  def show(self):
    print self.toString()
	
class Record:
  def __init__(self, filename, interval=86400, start_time=datetime(1999,8,1), 
               end_time=datetime.now()):
    self.filename = filename
    self.reader = csv.reader(open(filename))
    self.start_time = start_time
    self.end_time = end_time
    self.current_bar = None
    self.bars = None
    self._bars = None
    self.interval = 0
    self.setInterval(interval)
	  
  def setDateRange(self, start_time, end_time=datetime.now()):
    self.start_time = start_time
    selfend_time = end_time
    
  def setInterval(self, interval=86400):
    if self.interval == interval:
      print "interval is not changed, skip.."
      return
    
    self.interval = interval
    
    # only scan input file for the first time
    if self._bars is None:
      print "Haven't scanned before, do it now"
      self.scan()
      print "Scan Done. Totally %d bars"%(len(self._bars))
    
    # reset after "setInterval"
    self.current_bar = Bar(self._bars[0].time, \
                          self._bars[0].open, \
                          self._bars[0].close, \
                          self._bars[0].high, \
                          self._bars[0].low)
    self.bars = [self.current_bar]
    # _bar should be intact in the process
    for _bar in self._bars:
      if _bar.time < self.start_time or _bar.time > self.end_time:
        continue
      # Data will be inaccurate if self.interval is not a multiple of 
      # bar interval.
      
      if _bar.time.day <> self.current_bar.time.day or \
         _bar.time >= self.current_bar.time + timedelta(seconds=86400):
        self.current_bar = copy.copy(_bar)
        self.bars.append(self.current_bar) 
        #print "Adding bar: %s"%(self.current_bar.toString())
      else:
        #print "%s merges %s"%(self.current_bar.toString(), _bar.toString())
        self.current_bar.merge(_bar)
      
  # scan csv file from scratch
  def scan(self):
    self.counter = 0
    self._bars = []
    datePattern = re.compile(r'\d{4}\/\d{2}\/\d{2}')
    prev_data = None
    for row in self.reader:
      self.counter += 1
      if len(row) == 6:
        D,T,Open,Close,High,Low = row
      elif len(row) == 7:
        D,T,Open,Close,High,Low,Vol = row
      elif len(row) == 8:
        D,T,Open,Close,High,Low,Vol,OI = row
      else:
        continue
      
      if datePattern.search(D) is None:
        print "%s not match"%(D)
        continue
        
      data = [float(Open), float(Close), float(High), float(Low)]
      if data == prev_data:
        print "[%s] duplicate (probably off market?)"%(" ".join([D,T]))
        continue
        
      dt = datetime.strptime(" ".join([D,T]), "%Y/%m/%d %H:%M")
      bar = Bar(dt, data[0], data[1], data[2], data[3])
      # keep a copy in memory
      self._bars.append(copy.copy(bar))
      prev_data = copy.copy(data)
	
  def rewind(self):
    if len(self.bars) > 0:
      self.current_bar = self.bars[0]
    else:
      self.current_bar = None
    
  def traverse(self):
    for bar in self.bars:
      bar.show()
      
  def run_strategy(self, strategy):
    strategy.RunWithBars(self.bars)
      
	
def main():
  #record = Record('test.csv',86400)
  #print "First traverse"
  #record.traverse()
  #print "Second traverse"
  #record.setInterval(900)
  #record.traverse()
  record = Record('daily.csv')
  #record = Record('txf.csv')
  #record.traverse()
  record.run_strategy(MovingAverage())
  
if __name__ == "__main__":
  main()